(function () {
    //定义组件模板
    function createTemplate(count) {
        const template = document.createElement("template");
        template.innerHTML = `
            <style>
                .btn{
                    color: #fff;
                    background-color: #1890ff;
                    text-shadow: 0 -1px 0 rgba(0,0,0,.12);
                    box-shadow: 0 2px 0 rgba(0,0,0,.045);
                    outline: none;
                    border: none;
                    width: 32px;
                    height: 32px;
                    border-radius: 50%;
                    line-height: 1.5;
                    text-align: center;
                    font-size: 20px;
                    cursor: pointer;
                    transition: all 0.3s linear;
                }
                .btn:hover{
                    background: #0066CC;
                }
                .custom-button{
                    display: flex;
                    align-items: center;
                    justify-content: space-between;
                    width: 120px;
                    background: #E0E0E0;
                    border-radius: 16px;
                }
            </style>
            <div class="custom-button">
                <button class="btn" id="minus">
                     <slot name="minusBtnText">-</slot>
                </button>
                <span class="count" id="count">${count}</span>
                <button class="btn" id="plus">
                    <slot name="plusBtnText">+</slot>
                </button>
            </div>
        `
        return template;
    }

    //定义组件class
    class CustomStepper extends HTMLElement {
        /**
         * 此处联系到React/Vue中的完全受控组件
         * 为什么这里借助attribute来完成状态的存取？使用一个私有的内部变量也可以达成一样的效果
         * @returns {string | number}
         */
        get count() {
            return this.getAttribute("count") || 0;
        }

        set count(val) {
            this.setAttribute("count", val);
        }

        get min() {
            return this.getAttribute("min") || 0
        }

        get step() {
            return this.getAttribute("step") || 1
        }

        /**
         * 属性的监听...类似于手动指定依赖来完成依赖的收集，配合attributeChangedCallback来完成相关逻辑
         * @tips: 标签上直接声明的即为attribute,而document.getElementById("#id").X = Y,中的X即为property
         * @returns {string[]}
         */
        static get observedAttributes() {
            return ["count"]
        }

        //属性发生变化时的回调函数
        attributeChangedCallback(name, oldValue, newValue) {
            console.log(`监听到[${name}]发生变化:${oldValue}--->${newValue}`)
            if (name === "count") {
                this.countBox.textContent = newValue;
            }
        }

        connectedCallback() {
            console.log("connectedCallback is running...")
            this.minusButton.addEventListener("click", this.doMinus)
            this.plusButton.addEventListener("click", this.doPlus)
        }

        disconnectedCallback() {
            console.log("disconnectedCallback  is running...")
            this.minusButton.removeEventListener("click", this.doMinus)
            this.plusButton.removeEventListener("click", this.doPlus)
        }

        adoptedCallback() {
            console.log("adoptedCallback")
        }

        countBox = null

        doPlus = () => {
            //此处涉及到经典的string+number的问题，简单的用减法实现加法
            this.count = -(0 - this.step - this.count);
        }
        doMinus = () => {
            if (this.count - this.step < this.min) {
                if (this.onError && typeof this.onError === "function") {
                    this.onError("步进目标值小于设置的min")
                } else {
                    throw new Error("步进目标值小于设置的min")
                }
            }
            this.count -= this.step;
        }

        constructor() {
            //调用父类构造
            super();
            /**
             * 定义shadowDom
             * @mode: open | closed :是否拒绝从js外部访问关闭的shadow root节点
             * @type {ShadowRoot}
             */
            const shadowRoot = this.attachShadow({mode: "closed"});
            //避免污染模板，深拷贝template
            //tips:如果组件十分简单，可以直接指定shadowRoot内容：shadowRoot.innerHTML = something...
            shadowRoot.append(createTemplate(this.count).content.cloneNode(true));
            //事件监听
            this.minusButton = shadowRoot.querySelector("#minus")
            this.plusButton = shadowRoot.querySelector("#plus")
            this.countBox = shadowRoot.querySelector("#count")
        }
    }

    /**
     * 注册自定义组件
     * @tips:组件名为小写字母且必须含有至少一个中划线来和原生标签做区分
     */
    customElements.define("custom-stepper", CustomStepper)
    console.log("自定义组件[custom-stepper]注册完成")
})()